package it.hive.model;

import it.hive.controller.listener.TrackListener;
import it.hive.controller.task.CheckInternetConnection;
import it.hive.io.downloader.Downloader;
import it.hive.io.settings.beans.Impostazione;
import it.hive.mediaplayer.MediaPlayerController;
import it.hive.mediaplayer.beans.impl.Traccia;
import it.hive.model.common.ApplicationProperties;
import it.hive.model.common.constants.M2O_Default;
import it.hive.model.domain.io.DefaultDownloadDirectory;
import it.hive.model.domain.media.Gruppo;
import it.hive.model.domain.media.Trasmissione;
import it.hive.model.domain.net.InternetProxy;
import it.hive.model.io.net.parser.implementations.M2OParser;
import it.hive.model.io.net.parser.interfaces.Parser;
import it.hive.model.settings.ApplicationSettings;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;

import org.apache.commons.lang3.StringUtils;

public class Application {

	private static Application istanza;

	private volatile List<Gruppo> fasceOrarie;
	private volatile List<Trasmissione> trasmissioni;
	private volatile List<Traccia> trackList;

	private volatile HashMap<Gruppo, HashMap<Trasmissione, List<Traccia>>> parsedGroupCache;

	private Parser parser;

	private volatile TrackListener trackListener;

	private ApplicationSettings settings;

	private InternetProxy proxy;
	private DefaultDownloadDirectory defaultDirectory;

	/* ######################################################################### */
	private Application() {
		caricaConfigurazioni();
		init();
		checkInternetConnection();
	}

	private void init() {
		fasceOrarie = new ArrayList<>();
		trasmissioni = new ArrayList<>();
		trackList = new ArrayList<>();
		parser = new M2OParser();

		parsedGroupCache = new HashMap<Gruppo, HashMap<Trasmissione, List<Traccia>>>();

		ApplicationProperties.defaultDownloadDirectoryPath.set(defaultDirectory.getPathDefaultDirectory());
		ApplicationProperties.boolUsaSempreDefaultDownloadDirectory.set(defaultDirectory.usaSoloDefaultDirectory());

		ApplicationProperties.proxyIP.set(proxy.getProxyIP());
		ApplicationProperties.proxyPort.set(proxy.getProxyPort());
		ApplicationProperties.boolUsaProxy.set(!StringUtils.isBlank(proxy.getProxyIP()) && !StringUtils.isBlank(proxy.getProxyPort()));
		ApplicationProperties.downloadInCorso.set(false);

		ApplicationProperties.defaultDownloadDirectoryPath.addListener(new ChangeListener<String>() {
			@Override
			public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
				defaultDirectory.setPathDefaultDirectory(newValue);
			}
		});
		ApplicationProperties.boolUsaSempreDefaultDownloadDirectory.addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
				defaultDirectory.setUsaSoloDefaultDirectory(newValue != null ? newValue : false);
			}
		});

	}

	public static synchronized Application getIstanza() {
		if (istanza == null) {
			istanza = new Application();
		}
		return istanza;
	}

	private void caricaConfigurazioni() {
		settings = new ApplicationSettings();
		proxy = settings.getinternetProxy();
		defaultDirectory = settings.getDefaultDownloadDirectory();
	}

	private void checkInternetConnection() {
		CheckInternetConnection check = new CheckInternetConnection();
		ApplicationProperties.FrameTitle.bind(check.messageProperty());
		check.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
			@Override
			public void handle(WorkerStateEvent event) {
				recuperaGruppi();
				ApplicationProperties.FrameTitle.unbind();
			}
		});
	}

	/* ######################################################################### */
	public TrackListener getTrackListener() {
		if (trackListener == null) {
			trackListener = new TrackListener();
		}
		return trackListener;
	}

	/* ######################################################################### */

	public void parseHTML(URL playlistUrl) {

	}

	public boolean salvaConfigurazioni(Impostazione... impostazione) {
		return settings.salvaImpostazioni(impostazione);
	}

	public boolean salvaImpostazioniProxy(String proxyIP, String proxyPort) {
		proxy = new InternetProxy();
		proxy.setProxyIP(proxyIP);
		proxy.setProxyPort(proxyPort);
		checkInternetConnection();
		return salvaConfigurazioni(proxy);
	}

	public boolean salvaImpostazioniDefaultDownloadDirectory(String path, boolean usaSoloDefault) {
		defaultDirectory = new DefaultDownloadDirectory();
		defaultDirectory.setPathDefaultDirectory(path);
		defaultDirectory.setUsaSoloDefaultDirectory(usaSoloDefault);
		return salvaConfigurazioni(defaultDirectory);
	}

	public void recuperaGruppi() {
		if (fasceOrarie.isEmpty() && ApplicationProperties.internetConnection.get()) {
			try {
				fasceOrarie = parser.getGruppi(new URL(M2O_Default.M2O_RELOADED_URL));
				ApplicationProperties.observableGruppi.clear();
				ApplicationProperties.observableGruppi.addAll(fasceOrarie);
				for (Gruppo gruppo : fasceOrarie) {
					HashMap<Trasmissione, List<Traccia>> emptyMap = new HashMap<>();
					parsedGroupCache.put(gruppo, emptyMap);
				}
			} catch (MalformedURLException e) {
			}
		}
	}

	public void recuperaTrasmissioni(Gruppo gruppo) {
		HashMap<Trasmissione, List<Traccia>> cache;
		if ((cache = parsedGroupCache.get(gruppo)).isEmpty() && ApplicationProperties.internetConnection.get()) {
			trasmissioni.clear();
			trasmissioni = parser.getTrasmissioni(gruppo.getLinkGruppo());
			for (Trasmissione trasmissione : trasmissioni) {
				cache.put(trasmissione, new ArrayList<Traccia>());
				parsedGroupCache.put(gruppo, cache);
			}
		} else {
			trasmissioni.clear();
			trasmissioni.addAll(cache.keySet());
		}
		ApplicationProperties.observableTrasmissioni.clear();
		ApplicationProperties.observableTrasmissioni.addAll(trasmissioni);
	}

	public void recuperaTrackList(Gruppo gruppo, Trasmissione trasmissione) {
		HashMap<Trasmissione, List<Traccia>> cache;
		if (ApplicationProperties.internetConnection.get()) {
			if (!(cache = parsedGroupCache.get(gruppo)).isEmpty()) {
				if ((trackList = cache.get(trasmissione)).isEmpty()) {
					trackList = parser.getTrackList(trasmissione.getLinkTrasmissione());
					cache.put(trasmissione, trackList);
					parsedGroupCache.put(gruppo, cache);
				}
			} else {
				recuperaTrasmissioni(gruppo);
				recuperaTrackList(gruppo, trasmissione);
				return;
			}
			ApplicationProperties.observableTrackList.clear();
			ApplicationProperties.observableTrackList.addAll(trackList);
		}
	}

	public Traccia risolviURL(Traccia t) {
		if (ApplicationProperties.internetConnection.get()) {
			URL res = ((M2OParser) parser).risolviElemento(t.getUnparsedURL());
			t.setParsedURL(res);
		}
		return t;
	}

	public Downloader downloadMP3File(Traccia track) {
		String path = System.getProperty("user.home").endsWith("/") ? System.getProperty("user.home") : System.getProperty("user.home").concat("/");
		return new Downloader(track.getUrl(), path, track.getNomeTraccia() + ".mp3");
	}

	public Downloader downloadMP3File(Traccia track, String path) {
		if (path != null && ApplicationProperties.internetConnection.get()) {
			path = path.endsWith("/") ? path : path.concat("/");
			return new Downloader(track.getUrl(), path, track.getTrackName().concat(".mp3"));
		}
		return null;
	}

	public void chiudiApplicazione() {
		MediaPlayerController.getMediaPlayerController().stop();
		salvaConfigurazioni(proxy, defaultDirectory);
		System.exit(0);
	}

}
